package com.gin.supermarket_inventory_system.inventory.service;

import com.gin.security.utils.MySecurityUtils;
import com.gin.spring.exception.BusinessException;
import com.gin.supermarket_inventory_system.inventory.dto.form.receipt.ReceiptForm;
import com.gin.supermarket_inventory_system.inventory.dto.form.receipt.ReceiptFormDetail;
import com.gin.supermarket_inventory_system.inventory.dto.form.receipt.ReceiptFormExtra;
import com.gin.supermarket_inventory_system.inventory.entity.InventoryPo;
import com.gin.supermarket_inventory_system.inventory.entity.InventoryReceiptDetailPo;
import com.gin.supermarket_inventory_system.inventory.entity.InventoryReceiptPo;
import com.gin.supermarket_inventory_system.inventory.enums.InventoryReceiptType;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 库存数量服务
 * @since : 2023/10/11 15:49
 * @author : ginstone
 * @version : v1.0.0
 **/
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class InventoryAmountService {
    private final InventoryService inventoryService;
    private final InventoryReceiptService receiptService;
    private final InventoryReceiptDetailService detailService;


    /**
     * 提交单据表单: 销售，销售退货，盘点，耗损
     * @param form 表单
     * @param type 类型
     */
    public void submit(ReceiptForm form, InventoryReceiptType type) {
        if (type == InventoryReceiptType.PURCHASE || type == InventoryReceiptType.REJECT) {
            throw BusinessException.of(HttpStatus.BAD_REQUEST, "本方法不适用于该操作");
        }

        // 查询库存
        final Set<Long> inventoryId = form.getDetails().stream().map(ReceiptFormDetail::getInventoryId).collect(Collectors.toSet());
        final List<InventoryPo> inventoryList = inventoryService.listByIds(inventoryId);


        // 生成单据详情
        final List<InventoryReceiptDetailPo> details = form.getDetails().stream().map(f -> {
            final InventoryReceiptDetailPo d = f.toPo();

            // 设置价格，盘点和耗损为0，销售为正，退货为负
            inventoryList.stream().filter(i -> i.getId() == f.getInventoryId()).findFirst().ifPresent(i -> {
                // 销售退，价格为负
                if (type == InventoryReceiptType.CANCEL) {
                    d.setPrice(-1 * i.getPrice());
                }
                // 销售，复制价格
                if (type == InventoryReceiptType.SELL) {
                    d.setPrice(i.getPrice());
                }
            });
            // 计算总价
            d.calculateTotalPrice();
            return d;
        }).toList();

        //生成单据
        final InventoryReceiptPo receiptPo = form.toPo(type);


        saveData(receiptPo, details, inventoryList);
    }

    /**
     * 提交单据表单: 库存进货、库存退货
     * @param form 表单
     * @param type 类型
     */
    public void submit(ReceiptFormExtra form, InventoryReceiptType type) {
        if (type != InventoryReceiptType.PURCHASE && type != InventoryReceiptType.REJECT) {
            throw BusinessException.of(HttpStatus.BAD_REQUEST, "本方法不适用于该操作");
        }

        // 查询库存
        final Set<Long> inventoryId = form.getDetails().stream().map(ReceiptFormDetail::getInventoryId).collect(Collectors.toSet());
        final List<InventoryPo> inventoryList = inventoryService.listByIds(inventoryId);


        // 生成单据详情
        final List<InventoryReceiptDetailPo> details = form.getDetails().stream().map(f -> {
            final InventoryReceiptDetailPo d = f.toPo();

            // 设置价格，盘点和耗损为0，销售为正，退货为负
            inventoryList.stream().filter(i -> i.getId() == f.getInventoryId()).findFirst().ifPresent(i -> {
                // 销售退，价格为负
                if (type == InventoryReceiptType.PURCHASE) {
                    d.setPrice(-1 * i.getPrice());
                }
                // 销售，复制价格
                if (type == InventoryReceiptType.REJECT) {
                    d.setPrice(i.getPrice());
                }
            });
            // 计算总价
            d.calculateTotalPrice();
            return d;
        }).toList();

        //生成单据
        final InventoryReceiptPo receiptPo = form.toPo(type);


        saveData(receiptPo, details, inventoryList);
    }


    /**
     * 保存数据：单据，单据详情，库存数量
     * @param receiptPo 单据
     * @param details 单据详情
     * @param inventories 原始库存数据
     */
    private void saveData(InventoryReceiptPo receiptPo, List<InventoryReceiptDetailPo> details, List<InventoryPo> inventories) {
        // 操作人id
        receiptPo.setUserId(MySecurityUtils.currentUserDetails().getId());
        // 计算总价
        receiptPo.setTotalPrice(details.stream().mapToDouble(InventoryReceiptDetailPo::getTotalPrice).sum());
        // 保存单据
        receiptService.save(receiptPo);
        // 为单据详情设置单据id和类型
        details.forEach(i -> {
            i.setReceiptId(receiptPo.getId());
            i.setType(receiptPo.getType());
        });
        // 保存单据详情
        detailService.saveBatch(details);

        // 修改库存数量
        final List<InventoryPo> inventoryUpdate = inventories.stream().map(item -> {
            // 通过id匹配单据详情
            final InventoryReceiptDetailPo detail = details.stream().filter(i -> i.getInventoryId() == item.getId()).findFirst().orElse(null);
            if (detail != null) {
                final InventoryPo po = new InventoryPo();
                po.setId(item.getId());
                switch (receiptPo.getType()) {
                    // 进货, 销售退货
                    case PURCHASE, CANCEL -> po.setAmount(detail.getAmount() + item.getAmount());
                    // 库存退货，销售
                    case REJECT, SELL, DEPLETION -> po.setAmount(detail.getAmount() - item.getAmount());
                    // 盘点
                    case CHECK -> po.setAmount(item.getAmount());
                }

                if (receiptPo.getType() == InventoryReceiptType.CHECK) {
                    //盘点
                    po.setAmount(detail.getAmount());
                } else {
                    // 耗损
                    po.setAmount(item.getAmount() - detail.getAmount());
                }
                return po;
            }
            return null;
        }).filter(Objects::nonNull).toList();

        //更新修改库存数量信息
        if (!inventoryUpdate.isEmpty()) {
            inventoryService.updateBatchById(inventoryUpdate);
        }
    }
}
